/*
 * @Author: your name
 * @Date: 2021-07-01 15:55:11
 * @LastEditTime: 2021-07-03 17:45:42
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \Skip\assets\script\Game.ts
 */
// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

const { ccclass, property } = cc._decorator;

@ccclass
export default class Game extends cc.Component {

    // 脚本必传参数
    @property(cc.Prefab)
    RankingPrefab: cc.Prefab = null; // 排行榜单个预制体
    @property(cc.Prefab)
    blockPrefab: cc.Prefab = null; // 块预制体
    @property(cc.Node)
    hero: cc.Node = null; // hero外部的节点
    @property(cc.Node)
    hero_collision: cc.Node = null;// hero 里面的碰撞节点
    @property(cc.Node)
    gameOver: cc.Node = null;// 游戏结束节点
    @property(cc.Label)
    labelScore: cc.Label = null; // 分数节点
    @property(cc.Label)
    overScore: cc.Label = null; // 分数节点 结束时展示
    @property(cc.Label)
    bestScore: cc.Label = null; // 历史最高分 节点
    @property(cc.Node)
    gameOverRink: cc.Node = null; // 游戏结束排行版
    // 图集资源
    @property(cc.SpriteAtlas)
    avatars: cc.SpriteAtlas = null


    // 节点
    nodePHB: cc.Node = null; // 排行版 节点
    nodeReady: cc.Node = null; // 游戏主场景节点
    nodeScore: cc.Node = null; // 游戏分数上的节点

    leaderBoard: cc.Node = null; // 排行榜的主内容
    canvas: cc.Node = null; // 游戏全局节点


    // 对象池
    blockPool: cc.NodePool = new cc.NodePool(); // 创建块对象池
    // 全局对象
    static inst: Game = null; // 游戏脚本全局对象

    // 逻辑变量
    rinkingList = []; // 排行榜的数组
    gameStatus: number = 0; // 游戏状态 0 表示未开始 1开始游戏 2 结束游戏
    touchBlockBegin: boolean = false; // 是否开始点击 块 时间
    isTouchStart: boolean = false; // 是否开始按下
    isGetScore: number = -1;  // 该滑块是否已经得分
    moveDistance: number = 0; // hero线下缩放的距离
    currentScore: number = 0; // 游戏分值

    // 游戏入口
    onLoad() {
        this.canvas = cc.find("Canvas");
        this.nodePHB = cc.find("Canvas/NodePHB")
        this.nodeReady = cc.find("Canvas/NodeReady")
        this.nodeScore = cc.find("Canvas/NodeScore")
        this.gameOver.active = false;
        this.gameOver.zIndex = 9;
        this.nodePHB.zIndex = 10;
        this.nodeScore.active = false;
        this.nodePHB.active = false;
        this.hero.active = false;
        this.leaderBoard = cc.find("ScrollView/view/content", this.nodePHB);
        this.setAvatars();

        this.gameStatus = 0;
        this.setTouch();
        // 开启碰撞检测
        let manager = cc.director.getCollisionManager();
        manager.enabled = true;
        Game.inst = this;
    }
    // 游戏刷新
    update(dt) {
        if (this.touchBlockBegin && this.blockTouchStatus) {
            this.moveDistance++;
            if (this.moveDistance >= 400) {
                this.moveDistance = 400
            }
            let js = this.getCurrentBlock(2).getComponent("block")
            js.touchBegin(dt)
        } else {
            this.moveDistance = 0;
        }

    }
    // 设置交互事件
    setTouch() {
        this.canvas.on('touchstart', this.touchStart, this);
        this.canvas.on('touchmove', this.touchMove, this);
        this.canvas.on('touchend', this.touchEnd, this);
    }
    touchMove(e: cc.Event.EventTouch) {

    }
    touchStart(e: cc.Event.EventTouch) {
        this.hero_collision.active = false;
        // 当前是否是游戏进行中
        if (this.gameStatus !== 1) return;
        // Hero是否可点击
        if (!this.hero.getComponent("Hero").canTouch) return;
        // 判断滑块是否可点击
        if (!this.blockTouchStatus()) return;
        this.touchBlockBegin = true;
        this.isTouchStart = true
        this.isGetScore = -1;
        this.hero.angle = 0;
    }
    touchEnd(e: cc.Event.EventTouch) {
        // 当前是否是游戏进行中
        if (this.gameStatus !== 1) return;
        // 判断滑块是否可点击
        if (!this.blockTouchStatus()) return;
        // Hero是否可点击
        if (!this.hero.getComponent("Hero").canTouch) return;
        this.touchBlockBegin = false;
        this.isTouchStart = false
        // 回弹效果
        this.blockBack();
        this.heroJump()
    }
    // 游戏分发事件
    clickBtn(sender: cc.EventTarget, data: String) {
        switch (data) {
            case 'play':
                this.startGame();
                break;
            case 'phb':
                this.showRinkingBoard();
                break;
            case "closePHB":
                this.closeRinkingBoard();
                break;
            case "replay":
                this.clearBlock();
                this.startGame();
                break;
            case "gameover_phb":
                this.showRinkingBoard();
                break;
        }
    }
    // 开始游戏
    startGame() {
        cc.log("点击了开始")
        this.nodeScore.active = true;//开启分数展示
        this.nodeReady.active = false;//开启游戏
        this.nodePHB.active = false;// 隐藏排行榜
        this.gameOver.active = false; // 隐藏游戏结束节点
        this.gameStatus = 1;//初始化游戏状态
        this.currentScore = 0;// 初始化分数
        this.createBlock(cc.v2(-140, -240), 0, 1);
        this.createBlock(cc.v2(110, -100), 1, 2);
        this.hero.angle = 0;
        this.hero.active = true;
        this.hero.zIndex = 2;
        this.setHeroAction(cc.v2(-140, -240))
    }
    // 打开排行榜
    showRinkingBoard() {
        cc.log("点击了排行榜")
        this.addRankingItem();
        this.nodePHB.active = true;
    }
    // 关闭排行榜
    closeRinkingBoard() {
        cc.log("点击了排行榜关闭按钮")
        this.nodePHB.active = false;
    }
    // 更新分数
    updateScore(num) {
        this.currentScore += num;
        this.labelScore.string = this.currentScore.toString();
    }
    // 更新历史最高分
    updateBestScore() {
        let bestScore = cc.sys.localStorage.getItem('bestScore');
        if (!bestScore || bestScore < this.currentScore) {
            bestScore = this.currentScore
            cc.sys.localStorage.setItem('bestScore', bestScore);
        }
        this.bestScore.string = `历史最高分：${bestScore}`
    }
    // 清理屏幕的快
    clearBlock() {
        let children = this.canvas.children
        for (let i = children.length - 1; i >= 0; i--) {
            let js = children[i].getComponent("block");
            if (js) {
                this.destroyBlock(children[i])
            }
        }
    }
    // 展示游戏结束
    showGameOver() {
        // 更新 游戏结束时候的榜单数据；

        this.gameOver.active = true;
        this.updateBestScore();
        this.updateGameOverRink();
        this.overScore.string = this.currentScore.toString();
    }
    // 判断游戏是否结束
    isGameOver() {
        if (this.isGetScore === -1) {
            this.gameStatus = 2
            cc.log("踩空死亡");
            let startBlock = this.getCurrentBlock(2)
            let endBlock = this.getCurrentBlock(1)
            let endBlockPosition = endBlock.getComponent('block').position
            if (this.hero.y > endBlockPosition.y) {
                endBlock.zIndex = 3;
            } else {
                startBlock.zIndex = 3
            }
            this.hero_collision.active = false
            cc.tween(Game.inst.hero)
                .by(0.3, { y: -75 })
                .call(() => {
                    this.showGameOver()
                })
                .start()
        } else if (this.isGetScore === 0) {
            this.gameStatus = 2
            cc.log("滑到死亡");
            this.showGameOver()
        }
    }
    // 触发回弹效果
    blockBack() {
        let js = this.getCurrentBlock(2).getComponent("block")
        js.touchEnd()
    }
    // 判断是否需要添加快
    isAddBlock() {
        console.log('isAddBlock')
        let block = this.getCurrentBlock(1)
        let current = this.getCurrentBlock(2);
        let blockJS = block.getComponent("block")
        console.log(blockJS.isConllision)
        if (blockJS.isConllision) {
            // 添加新块
            this.addBlock();
        } else {
            // 不添加新块，并hero在的滑块可点击
            current.getComponent("block").canTouch = true;
        }
    }
    // hero跳跃的动作
    heroJump() {
        let lastNode = this.getCurrentBlock(1);
        let pos_last = lastNode !== null ? lastNode.getComponent("block").position : cc.v2(0, 0);
        let pos_hero = this.hero.getPosition()
        let f_rendom = this.moveDistance * 8;
        console.log(f_rendom)
        // 获得最后两个点的单位向量
        let pos_nor = pos_last.sub(pos_hero).normalize(); // 单位向量
        let pos_end = cc.v2(pos_hero.x + pos_nor.x * f_rendom, pos_hero.y + pos_nor.y * f_rendom + this.hero.height / 2); // 结束点位置
        let actStart = cc.callFunc(() => {
            this.hero.anchorY = 0.5;
            this.hero_collision.active = false
            this.hero.y = this.hero.y + this.hero.height / 2;
            this.hero.getComponent("Hero").canTouch = false;
        });
        let actJump = cc.jumpTo(0.6, pos_end, 200, 1);
        let actRotate = cc.rotateBy(0.6, 360);
        if (pos_nor.x < 0) {
            actRotate = cc.rotateBy(0.6, -360);
        }
        let actEnd = cc.callFunc(() => {
            this.hero.anchorY = 0;
            this.hero.y = this.hero.y - this.hero.height / 2;
            this.hero_collision.active = true
            this.hero.getComponent("Hero").canTouch = true;
            // 延时 
            this.scheduleOnce(() => {
                this.isGameOver()
                this.isAddBlock();
            }, 0.2)
            // 判断是否㤇添加新快
        });
        /**
         * 代码分析--
         * 由于一开始，锚点在底部，将锚点上移动导致锚点的位置到hero底部位置为 hero.height向下移动 
         * 因此在动作执行第一个步 修改锚点 1 修改位置 y+本身高度hero.height
         * 
         * 到达终点位置，需要将结束的点 位置 y+本身高度hero.height 不然会下移动 hero.height
         * 
         * 在跳跃块结束的时候，由于锚点 修改锚点 为0，到达终点位置，这个时候，位置在原来的基础上的+hero.height，需要减去
         */

        let actJumpAndRotate = cc.spawn(actJump, actRotate)
        let actCombine = cc.sequence(actStart, actJumpAndRotate, actEnd);
        this.hero.runAction(actCombine)
    }
    // hero进场动画
    setHeroAction(pos) {
        this.hero.setPosition(cc.v2(pos.x, pos.y + 200))
        this.hero.getComponent("Hero").canTouch = false;
        cc.tween(this.hero)
            .to(0.2, { y: pos.y - 10 })
            .to(0.08, { y: pos.y + 50 })
            .to(0.07, { y: pos.y - 5 })
            .to(0.06, { y: pos.y + 10 })
            .to(0.03, { y: pos.y })
            .call(() => {
                this.hero.getComponent("Hero").canTouch = true;
            })
            .start()
    }

    // 根据单位向量添加单个块
    addBlock() {
        let arrPoints = [];
        let children = this.canvas.children;
        // console.log(children)
        for (let i = children.length - 1; i >= 0; i--) {
            let js = children[i].getComponent("block");
            if (js) {
                // 将在屏幕上的块的白点相对位置 存入数组
                arrPoints.push(js.position)
            }
        }
        // 获得最后两个点的单位向量
        let pos_1 = arrPoints[0].sub(arrPoints[1]).normalize();
        // 随机方向
        if (Math.random() * 10 < 5) {
            pos_1.x = pos_1.x * -1;
        }
        // 距离随机数
        let f_rendom = 290 + Math.random() * 160

        // 添加第三个点的位置
        let pos_end = cc.v2(arrPoints[0].x + pos_1.x * f_rendom, arrPoints[0].y + pos_1.y * f_rendom);
        let blockType = Math.floor(Math.random() * 8); // 0-3的随机数
        // this.hero.setPosition(arrPoints[0].x, arrPoints[0].y);
        this.createBlock(pos_end, blockType, 3);


    }
    // 为添加的块添加入场动画
    blockMove() {
        this.touchBlockBegin = false;
        let arrPoints = [];
        let children = this.canvas.children;
        for (let i = children.length - 1; i >= 0; i--) {
            let js = children[i].getComponent("block");
            if (js) {
                // 将在屏幕上的块的白点相对位置 存入数组
                arrPoints.push(js.position)
            }
        }
        // 两点的中心点
        let pos_middle = cc.v2((arrPoints[0].x - arrPoints[1].x) / 2, (arrPoints[0].y - arrPoints[1].y) / 2);
        // 分别在x,y方向上移动了多少位置
        let pos_move = cc.v2(0 - (arrPoints[1].x + pos_middle.x), -150 - (arrPoints[1].y + pos_middle.y));
        children = this.canvas.children;
        cc.tween(this.hero)
            .by(0.5, { x: pos_move.x, y: pos_move.y > 0 ? -pos_move.y : pos_move.y })
            .call(() => {

            }).start();
        for (let i = children.length - 1; i >= 0; i--) {
            let js = children[i].getComponent("block");
            if (js) {
                if (js.position.y < -900) {
                    this.destroyBlock(children[i])
                    continue;
                }
                // 移动的动画
                cc.tween(children[i])
                    .by(0.5, { x: pos_move.x, y: pos_move.y > 0 ? -pos_move.y : pos_move.y })
                    .call(() => {
                        js.updatePosition()
                    }).start();
            }

        }

    }
    // 块当前的状态 是否可点击
    blockTouchStatus() {
        let children = this.canvas.children;
        for (let i = children.length - 1; i >= 0; i--) {
            let js = children[i].getComponent("block");
            if (js) {
                if (!js.canTouch) return false;
            }
        }
        return true
    }
    // 获取小人在的块 node
    getCurrentBlock(target) {
        let children = this.canvas.children
        let index = 0;
        for (let i = children.length - 1; i >= 0; i--) {
            let js = children[i].getComponent("block");
            if (js) {
                index++;
                if (index === target) return children[i];
            }
        }
        return null;
    }
    // 创建块
    createBlock(position: cc.Vec2, blockType: number, isFirst: number) {
        let node = this.blockPool.get();
        if (node === null) {
            node = cc.instantiate(this.blockPrefab);
        }
        node.zIndex = 0;
        this.canvas.addChild(node);
        node.getComponent("block").init(position, 0, isFirst)
        // let x = -300 + Math.random() * 600;
        // let y = -300 + Math.random() * 600;
        // node.setPosition(cc.v2(x, y))

        // return node;
    }
    // 回收块
    destroyBlock(node: cc.Node) {
        this.blockPool.put(node);
    }

    addRankingItem() {
        // 更新榜单数据
        this.updateRinkingList();
        // 升序后翻转数组
        this.rinkingList.sort(this.toSort('score'))

        let height = this.getRankingItem().height;
        // 移除下面的所有节点
        this.leaderBoard.removeAllChildren();
        this.leaderBoard.height = this.rinkingList.length * height
        for (let i = 0; i < this.rinkingList.length; i++) {
            // 添加排行榜，并且修改对应的高度
            let item = this.getRankingItem();
            item.y = -52 - i * height
            // 动态修改排行榜的内容
            let RankingItem = item.getComponent('RankingItem')
            // 初始化
            let nickname = this.rinkingList[i].nickname;
            let rinkNum = `${i + 1}`;
            let score = this.rinkingList[i].score
            let avatar = this.rinkingList[i].avatar
            RankingItem.init(nickname, rinkNum, score, avatar);
            // 节点挂载 content上
            this.leaderBoard.addChild(item)
        }
    }
    // 创建 排行榜单个
    getRankingItem() {
        let node = cc.instantiate(this.RankingPrefab);
        return node;
    }
    // 更新排行榜数据
    updateRinkingList() {
        let best = cc.sys.localStorage.getItem('bestScore')
        this.rinkingList.map(v => {
            if (v.nickname === "我") v.score = best || 0;
            return v;
        })
    }
    // 初始化 头像
    setAvatars() {
        this.rinkingList = [
            {
                nickname: '永远在一起',
                avatar: '1',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '喜歡伱那份〃温暖',
                avatar: '2',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '我',
                avatar: '3',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '我一直等着你出现',
                avatar: '4',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '玩笑往往藏着真心话',
                avatar: '5',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '最短的咒语',
                avatar: '6',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: 'King゜脉搏',
                avatar: '7',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '你是俄的歌',
                avatar: '8',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '深拥与我',
                avatar: '9',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '长相守',
                avatar: '10',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '走不出的是时光',
                avatar: '11',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '你是我的No 1',
                avatar: '12',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '狗比人衷',
                avatar: '13',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '痴心错付',
                avatar: '14',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '自己的旧年旋律',
                avatar: '15',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '折翼しé天使﹌',
                avatar: '16',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '莫气少年穷',
                avatar: '17',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '卌薆倪灬卟变丶',
                avatar: '18',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '与你共我',
                avatar: '19',
                score: Math.round(Math.random() * 100),
            },
            {
                nickname: '一日不见，如隔三秋',
                avatar: '20',
                score: Math.round(Math.random() * 100),
            },
        ];
    }
    // 更新 游戏结束时的排行榜
    updateGameOverRink() {
        this.updateRinkingList()
        this.rinkingList.sort(this.toSort('score'))
        let arr = []
        let index = this.rinkingList.findIndex(v => v.nickname === "我")
        if (index === this.rinkingList.length - 1) {
            arr = this.rinkingList.filter((v, i) => (i >= index - 2))
        } else {
            arr = this.rinkingList.filter((v, i) => ((i >= index - 1) && (i <= index + 1)))
        }
        arr.forEach((v, i) => {
            let item = this.gameOverRink.getChildByName(`rink_${i}`)
            item.getChildByName("rinkId").getComponent(cc.Label).string = (index + i - 1).toString();
            item.getChildByName("nickname").getComponent(cc.Label).string = v.nickname;
            item.getChildByName("score").getComponent(cc.Label).string = v.score;
            item.getChildByName("avatar").getComponent(cc.Sprite).spriteFrame = this.avatars.getSpriteFrame(`tou_${parseInt(v.avatar) - 1}`)
        })

    }
    // 降序
    toSort(propertyName) {
        return function (a, b) {
            // return a[propertyName] - b[propertyName]    // 升序
            return b[propertyName] - a[propertyName]    // 降序
        }
    }


}
